package chapter_17;


// 输入/输出：探究java.io


/*
17.1 Java输入/输出类和接口
 */


/*
17.2 File文件类
尽管java.io定义的大多数类是实行流式操作的，File类不是。它直接处理文件和文件系
统。也就是说，File类没有指定信息怎样从文件读取或向文件存储；它描述了文件本身的属
性。File对象用来获取或处理与磁盘文件相关的信息，例如权限，时间，日期和目录路径。
此外，File还浏览子目录层次结构。
很多程序中文件是数据的根源和目标。尽管它们在小应用程序中因为安全原因而受到
严格限制，文件仍是存储固定和共享信息的主要资源。Java中的目录当成File 对待，它具
有附加的属性——一个可以被 list( )方法检测的文件名列表。
下面的构造函数可以用来生成File 对象：
File(String directoryPath)
File(String directoryPath, String filename)
File(File dirObj, String filename)
这里，directoryPath是文件的路径名，filename 是文件名，dirObj 一个指定目录的File 对
象。
File 定义了很多获取File对象标准属性的方法。例如getName( )返回文件名，getParent( )
返回父目录名，exists( )在文件存在的情况下返回true，反之返回false。然而File类是不对称
的。说它不对称，意思是虽然存在允许验证一个简单文件对象属性的很多方法，但是没有
相应的函数来改变这些属性。

    17.2.1 目录
    目录是一个包含其他文件和路径列表的File 类。当你创建一个File 对象且它是目录时，
    isDirectory( ) 方法返回ture。这种情况下，可以调用该对象的list( )方法来提取该目录内部其
    他文件和目录的列表。该方法有两种形式。第一种形式如下：
    String[ ] list( )
    文件列表在一个String 对象数组中返回。

    17.2.2 使用FilenameFilter
    你总是希望能够限制由list( )方法返回的文件数目，使它仅返回那些与一定的文件名方
    式或者过滤(filter)相匹配的文件。为达到这样的目的，必须使用list( )的第二种形式：
    String[ ] list(FilenameFilter FFObj)
    该形式中，FFObj是一个实现FilenameFilter接口的类的对象。
    FilenameFilter仅定义了一个方法，accept( )。该方法被列表中的每个文件调用一次。它
    的通常形式如下：
    boolean accept(File directory, String filename)
    当被directory 指定的目录中的文件（也就是说，那些与filename 参数匹配的文件）包
    含在列表中时，accept( )方法返回true ，当这些文件没有包括在列表中时，accept( )返回false。
    下面显示的OnlyExt 类实现FilenameFilter接口，它被用来修饰前面的程序，限制由 list( )
    返回的文件名的可见度，把对象被创建时以指定扩展名结束的文件归档。

    17.2.3 listFiles()方法
    Java 2增加了list( )方法的一个变化形式，名为listFiles( )，你会发现该方法很有用。
    listFiles( )形式如下：
    File[ ] listFiles( )
    File[ ] listFiles(FilenameFilter FFObj)
    File[ ] listFiles(FileFilter FObj)
    上述三种形式以File对象矩阵的形式返回文件列表，而不是用字符串形式返回。第一种
    形式返回所有的文件，第二种形式返回满足指定FilenameFilter接口的文件。除了返回一个
    File 对象数组，这两个listFiles( )方法就像list( )方法一样工作。
    第三种listFiles( )形式返回满足指定FileFilter的路径名的文件。FileFilter只定义了一个
    accept( )方法，该方法被列表中的每个文件调用一次。它的通常形式如下：
    boolean accept(File path)
    如果文件被包括在列表中（即与path参数匹配的文件），accept( )方法返回true，如果
    不被包括，则返回false。

    17.2.4 创建目录
    另外两个有用的File类的方法是mkdir( )和mkdirs( )。mkdir( )方法创建了一个目录，创
    建成功返回true，创建失败返回false。创建失败是指File对象指定的目录已经存在，或者是
    因为整个路径不存在而不能创建目录。创建路径不存在的目录，用mkdirs( )的方法。它创
    建目录以及该目录所有的父目录。
 */


/*
17.3 流类
Java 的流式输入/输出建立在四个抽象类的基础上：InputStream, OutputStream, Reader
和Writer。
InputStream 和OutputStream 设计成字节流类。Reader 和Writer 为字符流设计。字节
流类和字符流类形成分离的层次结构。一般说来，处理字符或字符串时应使用字符流类，
处理字节或二进制对象时应用字节流类。
 */


/*
17.4 字节流
    17.4.1 InputStream（输入流）
    InputStream 是一个定义了Java流式字节输入模式的抽象类。该类的所有方法在出错条
    件下引发一个IOException 异常。

    17.4.2 OutputStream（输出流）
    OutputStream是定义了流式字节输出模式的抽象类。该类的所有方法返回一个void 值
    并且在出错情况下引发一个IOException异常。

    17.4.3 FileInputStream（文件输入流）
    FileInputStream 类创建一个能从文件读取字节的InputStream 类，它的两个常用的构造
    函数如下：
    FileInputStream(String filepath)
    FileInputStream(File fileObj)
    它们都能引发FileNotFoundException异常。这里，filepath 是文件的全称路径，fileObj
    是描述该文件的File对象。
    下面的例子创建了两个使用同样磁盘文件且各含一个上述构造函数的FileInputStreams
    类：
    FileInputStream f0 = new FileInputStream("/autoexec.bat")
    File f = new File("/autoexec.bat");
    FileInputStream f1 = new FileInputStream(f);
    尽管第一个构造函数可能更常用到，第二个构造函数允许在把文件赋给输入流之前用
    File方法更进一步检查文件。当一个FileInputStream被创建时，它可以被公开读取。
    FileInputStream重载了抽象类InputStream的六个方法，mark( )和reset( )方法不被重载，任何
    关于使用FileInputStream的reset()尝试都会生成IOException异常。

    17.4.4 FileOutputStream（文件输出流）
    FileOutputStream 创建了一个可以向文件写入字节的类OutputStream，它常用的构造函
    数如下：
    FileOutputStream(String filePath)
    FileOutputStream(File fileObj)
    FileOutputStream(String filePath, boolean append)
    它们可以引发IOException或SecurityException异常。这里filePath是文件的全称路径，
    fileObj是描述该文件的File对象。如果append为true，文件以设置搜索路径模式打开。
    FileOutputStream的创建不依赖于文件是否存在。在创建对象时FileOutputStream在打开
    输出文件之前创建它。这种情况下你试图打开一个只读文件，会引发一个IOException异常。

    17.4.5 ByteArrayInputStream（字节数组输入流）
    ByteArrayInputStream是把字节数组当成源的输入流。该类有两个构造函数，每个构造
    函数需要一个字节数组提供数据源：
    ByteArrayInputStream(byte array[ ])
    ByteArrayInputStream(byte array[ ], int start, int numBytes)
    这里，array是输入源。第二个构造函数创建了一个InputStream类，该类从字节数组的
    子集生成，以start指定索引的字符为起点，长度由numBytes决定。

    17.4.6 ByteArrayOutputStream（字节数组输出流）
    ByteArrayOutputStream是一个把字节数组当作输出流的实现。ByteArrayOutputStream
    有两个构造函数，如下：
    ByteArrayOutputStream( )
    ByteArrayOutputStream(int numBytes)
    在第一种形式里，一个32位字节的缓冲器被生成。第二个构造函数生成一个跟指定
    numBytes相同位数的缓冲器。缓冲器保存在ByteArrayOutputStream的受保护的buf 成员里。
    缓冲器的大小在需要的情况下会自动增加。缓冲器保存的字节数是由
    ByteArrayOutputStream的受保护的count域保存的。

    17.4.7 过滤字节流
    过滤流（filtered stream）仅仅是底层透明地提供扩展功能的输入流（输出流）的包装。
    这些流一般由普通类的方法（即过滤流的一个超类）访问。典型的扩展是缓冲，字符转换
    和原始数据转换。这些过滤字节流是FilterInputStream 和FilterOutputStream。它们的构造函
    数如下：
    FilterOutputStream(OutputStream os)
    FilterInputStream(InputStream is)
    这些类提供的方法和InputStream 及OutputStream类的方法相同。

    17.4.8 缓冲字节流
    对于字节流，缓冲流（buffered stream），通过把内存缓冲器连到输入/输出流扩展一个
    过滤流类。该缓冲器允许Java对多个字节同时进行输入/输出操作，提高了程序性能。因为
    缓冲器可用，所以可以跳过、标记和重新设置流。缓冲字节流类是BufferedInputStream 和
    BufferedOutputStream。PushbackInputStream 也可实现缓冲流。
    BufferedInputStream（缓冲输入流）
    缓冲输入/输出是一个非常普通的性能优化。Java 的BufferedInputStream 类允许把任何
    InputStream 类“包装”成缓冲流并使它的性能提高。
    BufferedInputStream 有两个构造函数：
    BufferedInputStream(InputStream inputStream)
    BufferedInputStream(InputStream inputStream, int bufSize)
    第一种形式生成了一个默认缓冲长度的缓冲流。第二种形式缓冲器大小是由bufSize传
    入的。使用内存页或磁盘块等的若干倍的缓冲区大小可以给执行性能带来很大的正面影响。
    但这是依赖于执行情况的。最理想的缓冲长度一般与主机操作系统、可用内存空间及机器
    配置有关。合理利用缓冲不需要特别复杂的操作。一般缓冲大小为8192个字节，给输入/输
    出流设定一个更小的缓冲器通常是好的方法。用这样的方法，低级系统可以从磁盘或网络
    读取数据块并在缓冲器中存储结果。因此，即使你在InputStream外同时读取字节数据时，
    也可以在超过99.9%的时间里获得快速存储操作。
    缓冲一个输入流同样提供了在可用缓冲器的流内支持向后移动的必备基础。除了在任
    何InputStream类中执行的read( )和skip( )方法外，BufferedInputStream 同样支持mark( )和
    reset( )方法。BufferedInputStream.markSupported( )返回true是这一支持的体现。

    BufferedOutputStream（缓冲输出流）
    BufferedOutputStream与任何一个OutputStream相同，除了用一个另外的flush( ) 方法来
    保证数据缓冲器被写入到实际的输出设备。因为BufferedOutputStream是通过减小系统写数
    据的时间而提高性能的，可以调用flush( )方法生成缓冲器中待写的数据。
    不像缓冲输入，缓冲输出不提供额外的功能，Java中输出缓冲器是为了提高性能的。
    下面是两个可用的构造函数：
    BufferedOutputStream(OutputStream outputStream)
    BufferedOutputStream(OutputStream outputStream, int bufSize)
    第一种形式创建了一个使用512字节缓冲器的缓冲流。第二种形式，缓冲器的大小由
    bufSize参数传入。

    PushbackInputStream（推回输入流）
    缓冲的一个新颖的用法是实现推回（pushback）。Pushback用于输入流允许字节被读取
    然后返回（即“推回”）到流。PushbackInputStream类实现了这个想法。它提供了一种机
    制来“窥视”在没有受到破坏的情况下输入流生成了什么。
    PushbackInputStream有两个构造函数：
    PushbackInputStream(InputStream inputStream)
    PushbackInputStream(InputStream inputStream, int numBytes)
    第一种形式创建了一个允许一个字节推回到输入流的流对象。第二种形式创建了一个
    具有numBytes长度缓冲区的推回缓冲流。它允许多个字节推回到输入流。
    除了具有与InputStream相同的方法，PushbackInputStream提供了unread( )方法，表示如
    下：
    void unread(int ch)
    void unread(byte buffer[ ])
    void unread(byte buffer, int offset, int numChars)
    第一种形式推回ch的低位字节，它将是随后调用read( )方法所返回的下一个字节。第二
    种形式返回buffer缓冲器中的字节。第三种形式推回buffer中从offset处开始的numChars个字
    节。如果在推回缓冲器为满时试图返回一个字节，IOException异常将被引发。

    17.4.9 SequenceInputStream（顺序输入流）
    SequenceInputStream类允许连接多个InputStream流。SequenceInputStream的构造不同于
    任何其他的InputStream。SequenceInputStream构造函数要么使用一对InputStream，要么用
    InputStream的一个Enumeration，显示如下：
    SequenceInputStream(InputStream first, InputStream second)
    SequenceInputStream(Enumeration streamEnum)
    操作上来说，该类满足读取完第一个InputStream后转去读取第二个流的读取要求。使
    用Enumeration的情况下，它将继续读取所有InputStream流直到最后一个被读完。

    17.4.10 PrintStream（打印流）
    PrintStream具有本书开始以来我们在System文件句柄使用过的System.out所有的格式
    化性能。PrintStream有两个构造函数：
    PrintStream(OutputStream outputStream)
    PrintStream(OutputStream outputStream, boolean flushOnNewline)
    当flushOnNewline 控制Java 每次刷新输出流时，输出一个换行符（ \n ）。如果
    flushOnNewline为true，自动刷新。若为false，刷新不能自动进行。第一个构造函数不支持
    自动刷新。
    Java的PrintStream对象支持包括Object在内的各种类型的 print( ) 和 println( )方法。如
    果参数不是一个简单类型，PrintStream方法将调用对象的 toString( ) 方法，然后打印结果。

    17.4.11 RandomAccessFile（随机访问文件类）
    RandomAccessFile 包装了一个随机访问的文件。它不是派生于InputStream 和
    OutputStream，而是实现定义了基本输入/输出方法的DataInput和DataOutput接口。它同样支
    持定位请求——也就是说，可以在文件内部放置文件指针。它有两个构造函数：
    RandomAccessFile(File fileObj, String access)
    throws FileNotFoundException
    RandomAccessFile(String filename, String access)
    throws FileNotFoundException
    第一种形式，fileObj指定了作为File 对象打开的文件的名称。第二种形式，文件名是
    由filename参数传入的。两种情况下，access 都决定允许访问何种文件类型。如果是“r”，
    那么文件可读不可写，如果是“rw”，文件以读写模式打开。
    下面所示的seek( )方法，用来设置文件内部文件指针的当前位置：
    void seek(long newPos) throws IOException
    这里，newPos 指文件指针从文件开始以字节方式指定新位置。调用seek( )方法后，接
    下来的读或写操作将在文件的新位置发生。
    RandomAccessFile 实现了用来读写随机访问文件的标准的输入和输出方法。下面是
    Java 2增添的新方法setLength( )。它有下面的形式：
    void setLength(long len) throws IOException
    该方法通过指定的len设置正在调用的文件的长度。该方法可以增长或缩短一个文件。
    如果文件被加长，增加的部分是未定义的。
 */


/*
17.5 字符流
尽管字节流提供了处理任何类型输入/输出操作的足够的功能，它们不能直接操作
Unicode字符。既然Java的一个主要目的是支持“只写一次，到处运行”的哲学，包括直接
的字符输入／输出支持是必要的。本节将讨论几个字符输入／输出类。如前所述，字符流
层次结构的顶层是Reader 和Writer 抽象类。
    17.5.1 Reader
    Reader是定义Java的流式字符输入模式的抽象类。该类的所有方法在出错情况下都将引
    发IOException 异常。

    17.5.2 Writer
    Writer 是定义流式字符输出的抽象类。所有该类的方法都返回一个void 值并在出错条
    件下引发IOException 异常。

    17.5.3 FileReader
    FileReader类创建了一个可以读取文件内容的Reader类。它最常用的构造函数显示如
    下：
    FileReader(String filePath)
    FileReader(File fileObj)
    每一个都能引发一个FileNotFoundException异常。这里，filePath是一个文件的完整路
    径，fileObj是描述该文件的File 对象。

    17.5.4 FileWriter
    FileWriter 创建一个可以写文件的Writer 类。它最常用的构造函数如下：
    FileWriter(String filePath)
    FileWriter(String filePath, boolean append)
    FileWriter(File fileObj)
    它们可以引发IOException或SecurityException异常。这里，filePath是文件的完全路径，
    fileObj是描述该文件的File对象。如果append为true，输出是附加到文件尾的。
    FileWriter类的创建不依赖于文件存在与否。在创建文件之前，FileWriter将在创建对象
    时打开它来作为输出。如果你试图打开一个只读文件，将引发一个IOException异常。

    17.5.5 CharArrayReader
    CharArrayReader 是一个把字符数组作为源的输入流的实现。该类有两个构造函数，每
    一个都需要一个字符数组提供数据源：
    CharArrayReader(char array[ ])
    CharArrayReader(char array[ ], int start, int numChars)
    这里，array是输入源。第二个构造函数从你的字符数组的子集创建了一个Reader，该
    子集以start指定的索引开始，长度为numChars。

    17.5.6 CharArrayWriter
    CharArrayWriter 实现了以数组作为目标的输出流。CharArrayWriter 有两个构造函数：
    CharArrayWriter( )
    CharArrayWriter(int numChars)
    第一种形式，创建了一个默认长度的缓冲器。第二种形式，缓冲器长度由numChars指
    定。缓冲器保存在CharArrayWriter的buf 成员中。缓冲器大小在需要的情况下可以自动增
    长。缓冲器保持的字符数包含在CharArrayWriter的count 成员中。buf 和count 都是受保护
    的域。

    17.5.7 BufferedReader
    BufferedReader 通过缓冲输入提高性能。它有两个构造函数：
    BufferedReader(Reader inputStream)
    BufferedReader(Reader inputStream, int bufSize)
    第一种形式创建一个默认缓冲器长度的缓冲字符流。第二种形式，缓冲器长度由bufSize
    传入。
    和字节流的情况相同，缓冲一个输入字符流同样提供支持可用缓冲器中流内反向移动
    的基础。为支持这点， BufferedReader 实现了mark( ) 和reset( ) 方法， 并且Buffered
    Reader.markSupported( ) 返回true.。

    17.5.8 BufferedWriter
    BufferedWriter是一个增加了flush( )方法的Writer。flush( )方法可以用来确保数据缓冲器
    确实被写到实际的输出流。用BufferedWriter 可以通过减小数据被实际的写到输出流的次
    数而提高程序的性能。
    BufferedWriter有两个构造函数：
    BufferedWriter(Writer outputStream)
    BufferedWriter(Writer outputStream, int bufSize)
    第一种形式创建了使用默认大小缓冲器的缓冲流。第二种形式中，缓冲器大小是由
    bufSize参数传入的。

    17.5.9 PushbackReader
    PushbackReader类允许一个或多个字符被送回输入流。这使你可以对输入流进行预测。
    下面是它的两个构造函数：
    PushbackReader(Reader inputStream)
    PushbackReader(Reader inputStream, int bufSize)
    第一种形式创建了一个允许单个字节被推回的缓冲流。第二种形式，推回缓冲器的大
    小由bufSize参数传入。
    PushbackReader 提供了unread( )方法。该方法返回一个或多个字符到调用的输入流。
    它有下面的三种形式：
    void unread(int ch)
    void unread(char buffer[ ])
    void unread(char buffer[ ], int offset, int numChars)
    第一种形式推回ch传入的字符。它是被并发调用的read( )返回的下一个字符。第二种形
    式返回buffer中的字符。第三种形式推回buffer中从offset开始的numChars 个字符。如果在
    推回缓冲器为满的条件下试图返回一个字符，一个IOException异常将被引发。

    17.5.10 PrintWriter
    PrintWriter本质上是PrintStream的字符形式的版本。它提供格式化的输出方法print( )和
    println( )。PrintWriter有四个构造函数：
    PrintWriter(OutputStream outputStream)
    PrintWriter(OutputStream outputStream, boolean flushOnNewline)
    PrintWriter(Writer outputStream)
    PrintWriter(Writer outputStream, boolean flushOnNewline)
    flushOnNewline 控制Java 是否在每次输出换行符（ \n ） 时刷新输出流。如果
    flushOnNewline为true，刷新自动发生。若为false，不进行自动刷新。第一个和第三个构造
    函数不能自动刷新。
    Java的PrintWriter对象支持包括用于Object在内的各种类型的print( )和println( )方法。如
    果语句不是一个简单类型，PrintWriter的方法将调用对象的toString（）方法，然后输出结
    果。
 */


/*
17.6 使用流式输入/输出

 */


/*
17.7 序列化
序列化（serialization）是把一个对象的状态写入一个字节流的过程。当你想要把你的
程序状态存到一个固定的存储区域例如文件时，它是很管用的。稍后一点时间，你就可以
运用序列化过程存储这些对象。
序列化也要执行远程方法调用（RMI）。RMI允许一台机器上的Java对象调用不同机器
上的Java 对象方法。对象可以作为一个参数提供给那个远程方法。发送机序列化该对象并
传送它。接受机反序列化它。
假设一个被序列化的对象引用了其他对象，同样，其他对象又引用了更多的对象。这
一系列的对象和它们的关系形成了一个顺序图表。在这个对象图表中也有循环引用。也就
是说，对象X可以含有一个对象Y的引用，对象Y同样可以包含一个对象X的引用。对象同
样可以包含它们自己的引用。对象序列化和反序列化的工具被设计出来并在这一假定条件
下运行良好。如果你试图序列化一个对象图表中顶层的对象，所有的其他的引用对象都被
循环的定位和序列化。同样，在反序列化过程中，所有的这些对象以及它们的引用都被正
确的恢复。
    17.7.1 Serializable接口
    只有一个实现Serializable接口的对象可以被序列化工具存储和恢复。Serializable接口没
    有定义任何成员。它只用来表示一个类可以被序列化。如果一个类可以序列化，它的所有
    子类都可以序列化。
    声明成transient的变量不被序列化工具存储。同样，static变量也不被存储。

    17.7.2 Externalizable接口
    Java的序列化和反序列化的工具被设计出来，所以很多存储和恢复对象状态的工作自
    动进行。然而，在某些情况下，程序员必须控制这些过程。例如，在需要使用压缩或加密
    技术时，Externalizable接口为这些情况而设计。
    Externalizable 接口定义了两个方法：
    void readExternal(ObjectInput inStream)
    throws IOException, ClassNotFoundException
    void writeExternal(ObjectOutput outStream)
    throws IOException
    这些方法中，inStream是对象被读取的字节流，outStream是对象被写入的字节流。

    17.7.3 ObjectOutput接口
    ObjectOutput 继承DataOutput接口并且支持对象序列化。特别注意writeObject( )方法，
    它被称为序列化一个对象。所有这些方法在出错情况下引发IOException 异常。

    17.7.4 ObjectOutputStream类
    ObjectOutputStream类继承OutputStream 类和实现ObjectOutput 接口。它负责向流写入
    对象。该类的构造函数如下：
    ObjectOutputStream(OutputStream outStream) throws IOException
    参数outStream 是序列化的对象将要写入的输出流。

    17.7.5 ObjectInput
    ObjectInput 接口继承DataInput接口并且定义了一些方法。它支持对象序列化。
    特别注意 readObject( )方法，它叫反序列化对象。所有这些方法在出错情况下引发
    IOException 异常。

    17.7.6 ObjectInputStream
    ObjectInputStream 继承InputStream 类并实现ObjectInput 接口。ObjectInputStream 负
    责从流中读取对象。该类的构造函数如下：
    ObjectInputStream(InputStream inStream)
    throws IOException, StreamCorruptedException
    参数inStream 是序列化对象将被读取的输入流。

    17.7.7 序列化示例
 */


/*
17.8 流的益处
Java的输入输出的流式接口为复杂而繁重的任务提供了一个简洁的抽象。过滤流类的
组合允许你动态建立客户端流式接口来配合数据传输要求。继承高级流类InputStream、
InputStreamReader、Reader和Writer 类的Java程序在将来（即使创建了新的和改进的具体类）
也能得到合理运用。
 */


public class chapter_17 {

}
